home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-19 / gpt32src.zip / GRAPHICS.C < prev    next >
C/C++ Source or Header  |  1992-03-25  |  44KB  |  1,567 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: graphics.c,v 3.26 92/03/24 22:34:25 woo Exp Locker: woo $";
  3. #endif
  4.  
  5. /* GNUPLOT - graphics.c */
  6. /*
  7.  * Copyright (C) 1986, 1987, 1990, 1991, 1992   Thomas Williams, Colin Kelley
  8.  *
  9.  * Permission to use, copy, and distribute this software and its
  10.  * documentation for any purpose with or without fee is hereby granted, 
  11.  * provided that the above copyright notice appear in all copies and 
  12.  * that both that copyright notice and this permission notice appear 
  13.  * in supporting documentation.
  14.  *
  15.  * Permission to modify the software is granted, but not the right to
  16.  * distribute the modified code.  Modifications are to be distributed 
  17.  * as patches to released version.
  18.  *  
  19.  * This software is provided "as is" without express or implied warranty.
  20.  * 
  21.  *
  22.  * AUTHORS
  23.  * 
  24.  *   Original Software:
  25.  *     Thomas Williams,  Colin Kelley.
  26.  * 
  27.  *   Gnuplot 2.0 additions:
  28.  *       Russell Lang, Dave Kotz, John Campbell.
  29.  *
  30.  *   Gnuplot 3.0 additions:
  31.  *       Gershon Elber and many others.
  32.  * 
  33.  * Send your comments or suggestions to 
  34.  *  info-gnuplot@ames.arc.nasa.gov.
  35.  * This is a mailing list; to join it send a note to 
  36.  *  info-gnuplot-request@ames.arc.nasa.gov.  
  37.  * Send bug reports to
  38.  *  bug-gnuplot@ames.arc.nasa.gov.
  39.  */
  40.  
  41. #include <stdio.h>
  42. #include <math.h>
  43. #include <assert.h>
  44. #include <time.h>
  45. #include "plot.h"
  46. #include "setshow.h"
  47.  
  48. extern char *strcpy(),*strncpy(),*strcat(),*ctime();
  49. char *tdate;
  50. #ifdef AMIGA_AC_5
  51. time_t dated;
  52. #else
  53. #ifdef VMS
  54. time_t dated,time();
  55. #else
  56. long dated,time();
  57. #endif
  58. #endif
  59.  
  60. void plot_impulses();
  61. void plot_lines();
  62. void plot_points();
  63. void plot_dots();
  64. void plot_bars();
  65. void edge_intersect();
  66. BOOLEAN two_edge_intersect();
  67.  
  68. /* for plotting error bars */
  69. #define ERRORBARTIC (t->h_tic/2) /* half the width of error bar tic mark */
  70.  
  71. #ifndef max        /* Lattice C has max() in math.h, but shouldn't! */
  72. #define max(a,b) ((a > b) ? a : b)
  73. #endif
  74.  
  75. #ifndef min
  76. #define min(a,b) ((a < b) ? a : b)
  77. #endif
  78.  
  79. #define inrange(z,min,max) ((min<max) ? ((z>=min)&&(z<=max)) : ((z>=max)&&(z<=min)) )
  80.  
  81. /* True if a and b have the same sign or zero (positive or negative) */
  82. #define samesign(a,b) ((a) * (b) >= 0)
  83.  
  84. /* Define the boundary of the plot
  85.  * These are computed at each call to do_plot, and are constant over
  86.  * the period of one do_plot. They actually only change when the term
  87.  * type changes and when the 'set size' factors change. 
  88.  */
  89. static int xleft, xright, ybot, ytop;
  90.  
  91. /* Boundary and scale factors, in user coordinates */
  92. /* x_min, x_max, y_min, y_max are local to this file and
  93.  * are not the same as variables of the same names in other files
  94.  */
  95. static double x_min, x_max, y_min, y_max;
  96. static double xscale, yscale;
  97.  
  98. /* And the functions to map from user to terminal coordinates */
  99. #define map_x(x) (int)(xleft+(x-x_min)*xscale+0.5) /* maps floating point x to screen */ 
  100. #define map_y(y) (int)(ybot+(y-y_min)*yscale+0.5)    /* same for y */
  101.  
  102. /* (DFK) Watch for cancellation error near zero on axes labels */
  103. #define SIGNIF (0.01)        /* less than one hundredth of a tic mark */
  104. #define CheckZero(x,tic) (fabs(x) < ((tic) * SIGNIF) ? 0.0 : (x))
  105. #define NearlyEqual(x,y,tic) (fabs((x)-(y)) < ((tic) * SIGNIF))
  106.  
  107. /* (DFK) For some reason, the Sun386i compiler screws up with the CheckLog 
  108.  * macro, so I write it as a function on that machine.
  109.  */
  110. #ifndef sun386
  111. /* (DFK) Use 10^x if logscale is in effect, else x */
  112. #define CheckLog(log, x) ((log) ? pow(10., (x)) : (x))
  113. #else
  114. static double
  115. CheckLog(log, x)
  116.      BOOLEAN log;
  117.      double x;
  118. {
  119.   if (log)
  120.     return(pow(10., x));
  121.   else
  122.     return(x);
  123. }
  124. #endif /* sun386 */
  125.  
  126. double
  127. LogScale(coord, islog, what, axis)
  128.     double coord;            /* the value */
  129.     BOOLEAN islog;            /* is this axis in logscale? */
  130.     char *what;            /* what is the coord for? */
  131.     char *axis;            /* which axis is this for ("x" or "y")? */
  132. {
  133.     if (islog) {
  134.        if (coord <= 0.0) {
  135.           char errbuf[100];        /* place to write error message */
  136.         (void) sprintf(errbuf,"%s has %s coord of %g; must be above 0 for log scale!",
  137.                 what, axis, coord);
  138.           (*term_tbl[term].text)();
  139.           (void) fflush(outfile);
  140.           int_error(errbuf, NO_CARET);
  141.        } else
  142.         return(log10(coord));
  143.     }
  144.     return(coord);
  145. }
  146.  
  147. /* borders of plotting area */
  148. /* computed once on every call to do_plot */
  149. boundary(scaling)
  150.     BOOLEAN scaling;        /* TRUE if terminal is doing the scaling */
  151. {
  152.     register struct termentry *t = &term_tbl[term];
  153.     xleft = (t->h_char)*12;
  154.     xright = (scaling ? 1 : xsize) * (t->xmax) - (t->h_char)*2 - (t->h_tic);
  155.     ybot = (t->v_char)*7/2 + 1;
  156.     ytop = (scaling ? 1 : ysize) * (t->ymax) - (t->v_char)*5/2 - 1;
  157. }
  158.  
  159.  
  160. double dbl_raise(x,y)
  161. double x;
  162. int y;
  163. {
  164. register int i;
  165. double val;
  166.  
  167.     val = 1.0;
  168.     for (i=0; i < abs(y); i++)
  169.         val *= x;
  170.     if (y < 0 ) return (1.0/val);
  171.     return(val);
  172. }
  173.  
  174.  
  175. double make_tics(tmin,tmax,logscale)
  176. double tmin,tmax;
  177. BOOLEAN logscale;
  178. {
  179. register double xr,xnorm,tics,tic,l10;
  180.  
  181.     xr = fabs(tmin-tmax);
  182.     
  183.     l10 = log10(xr);
  184.     if (logscale) {
  185.         tic = dbl_raise(10.0,(l10 >= 0.0 ) ? (int)l10 : ((int)l10-1));
  186.         if (tic < 1.0)
  187.             tic = 1.0;
  188.     } else {
  189.         xnorm = pow(10.0,l10-(double)((l10 >= 0.0 ) ? (int)l10 : ((int)l10-1)));
  190.         if (xnorm <= 2)
  191.             tics = 0.2;
  192.         else if (xnorm <= 5)
  193.             tics = 0.5;
  194.         else tics = 1.0;    
  195.         tic = tics * dbl_raise(10.0,(l10 >= 0.0 ) ? (int)l10 : ((int)l10-1));
  196.     }
  197.     return(tic);
  198. }
  199.  
  200.  
  201. do_plot(plots, pcount, min_x, max_x, min_y, max_y)
  202. struct curve_points *plots;
  203. int pcount;            /* count of plots in linked list */
  204. double min_x, max_x;
  205. double min_y, max_y;
  206. {
  207. register struct termentry *t = &term_tbl[term];
  208. register int curve, xaxis_y, yaxis_x;
  209. register struct curve_points *this_plot;
  210. register double ytic, xtic;
  211. register int xl, yl;
  212.             /* only a Pyramid would have this many registers! */
  213. double xtemp, ytemp;
  214. struct text_label *this_label;
  215. struct arrow_def *this_arrow;
  216. BOOLEAN scaling;
  217.  
  218. /* store these in variables global to this file */
  219. /* otherwise, we have to pass them around a lot */
  220.      x_min = min_x;
  221.      x_max = max_x; 
  222.      y_min = min_y;
  223.      y_max = max_y;
  224.  
  225.     if (polar) {
  226.         /* will possibly change x_min, x_max, y_min, y_max */
  227.         polar_xform(plots,pcount);
  228.     }
  229.  
  230.     if (y_min == VERYLARGE || y_max == -VERYLARGE ||
  231.         x_min == VERYLARGE || x_max == -VERYLARGE)
  232.         int_error("all points undefined!", NO_CARET);
  233.  
  234. /*    Apply the desired viewport offsets. */
  235.      if (y_min < y_max) {
  236.         y_min -= boff;
  237.         y_max += toff;
  238.     } else {
  239.         y_max -= boff;
  240.         y_min += toff;
  241.     }
  242.      if (x_min < x_max) {
  243.         x_min -= loff;
  244.         x_max += roff;
  245.     } else {
  246.         x_max -= loff;
  247.         x_min += roff;
  248.     }
  249.  
  250. /* SETUP RANGES, SCALES AND TIC PLACES */
  251.     if (ytics && yticdef.type == TIC_COMPUTED) {
  252.        ytic = make_tics(y_min,y_max,log_y);
  253.     
  254.        if (autoscale_ly) {
  255.           if (y_min < y_max) {
  256.              y_min = ytic * floor(y_min/ytic);       
  257.              y_max = ytic * ceil(y_max/ytic);
  258.           }
  259.           else {            /* reverse axis */
  260.              y_min = ytic * ceil(y_min/ytic);       
  261.              y_max = ytic * floor(y_max/ytic);
  262.           }
  263.        }
  264.     }
  265.  
  266.     if (xtics && xticdef.type == TIC_COMPUTED) {
  267.        xtic = make_tics(x_min,x_max,log_x);
  268.        
  269.        if (autoscale_lx) {
  270.           if (x_min < x_max) {
  271.              x_min = xtic * floor(x_min/xtic);    
  272.              x_max = xtic * ceil(x_max/xtic);
  273.           } else {
  274.              x_min = xtic * ceil(x_min/xtic);
  275.              x_max = xtic * floor(x_max/xtic);    
  276.           }
  277.        }
  278.     }
  279.  
  280. /*    This used be x_max == x_min, but that caused an infinite loop once. */
  281.     if (fabs(x_max - x_min) < zero)
  282.         int_error("x_min should not equal x_max!",NO_CARET);
  283.     if (fabs(y_max - y_min) < zero)
  284.         int_error("y_min should not equal y_max!",NO_CARET);
  285.  
  286. /* INITIALIZE TERMINAL */
  287.     if (!term_init) {
  288.         (*t->init)();
  289.         term_init = TRUE;
  290.     }
  291.     screen_ok = FALSE;
  292. #ifdef AMIGA_LC_5_1
  293.      scaling = (*t->scale)((double)xsize, (double)ysize);
  294. #else
  295.      scaling = (*t->scale)(xsize, ysize);
  296. #endif
  297.     (*t->graphics)();
  298.  
  299.      /* now compute boundary for plot (xleft, xright, ytop, ybot) */
  300.      boundary(scaling);
  301.  
  302. /* SCALE FACTORS */
  303.     yscale = (ytop - ybot)/(y_max - y_min);
  304.     xscale = (xright - xleft)/(x_max - x_min);
  305.     
  306. /* DRAW AXES */
  307.     (*t->linetype)(-1);    /* axis line type */
  308.     xaxis_y = map_y(0.0);
  309.     yaxis_x = map_x(0.0); 
  310.  
  311.     if (xaxis_y < ybot)
  312.         xaxis_y = ybot;                /* save for impulse plotting */
  313.     else if (xaxis_y >= ytop)
  314.         xaxis_y = ytop ;
  315.     else if (xzeroaxis && !log_y) {
  316.         (*t->move)(xleft,xaxis_y);
  317.         (*t->vector)(xright,xaxis_y);
  318.     }
  319.  
  320.     if (yzeroaxis && !log_x && yaxis_x >= xleft && yaxis_x < xright ) {
  321.         (*t->move)(yaxis_x,ybot);
  322.         (*t->vector)(yaxis_x,ytop);
  323.     }
  324.  
  325. /* DRAW TICS */
  326.     (*t->linetype)(-2); /* border linetype */
  327.  
  328.     /* label y axis tics */
  329.      if (ytics) {
  330.         switch (yticdef.type) {
  331.            case TIC_COMPUTED: {
  332.                if (y_min < y_max)
  333.                 draw_ytics(ytic * floor(y_min/ytic),
  334.                         ytic,
  335.                         ytic * ceil(y_max/ytic));
  336.               else
  337.                 draw_ytics(ytic * floor(y_max/ytic),
  338.                         ytic,
  339.                         ytic * ceil(y_min/ytic));
  340.  
  341.               break;
  342.            }
  343.            case TIC_SERIES: {
  344.               draw_series_ytics(yticdef.def.series.start, 
  345.                             yticdef.def.series.incr, 
  346.                             yticdef.def.series.end);
  347.               break;
  348.            }
  349.            case TIC_USER: {
  350.               draw_set_ytics(yticdef.def.user);
  351.               break;
  352.            }
  353.            default: {
  354.               (*t->text)();
  355.                 (void) fflush(outfile);
  356.               int_error("unknown tic type in yticdef in do_plot", NO_CARET);
  357.               break;        /* NOTREACHED */
  358.            }
  359.         }
  360.     }
  361.  
  362.     /* label x axis tics */
  363.      if (xtics) {
  364.         switch (xticdef.type) {
  365.            case TIC_COMPUTED: {
  366.                if (x_min < x_max)
  367.                 draw_xtics(xtic * floor(x_min/xtic),
  368.                         xtic,
  369.                         xtic * ceil(x_max/xtic));
  370.               else
  371.                 draw_xtics(xtic * floor(x_max/xtic),
  372.                         xtic,
  373.                         xtic * ceil(x_min/xtic));
  374.  
  375.               break;
  376.            }
  377.            case TIC_SERIES: {
  378.               draw_series_xtics(xticdef.def.series.start, 
  379.                             xticdef.def.series.incr, 
  380.                             xticdef.def.series.end);
  381.               break;
  382.            }
  383.            case TIC_USER: {
  384.               draw_set_xtics(xticdef.def.user);
  385.               break;
  386.            }
  387.            default: {
  388.               (*t->text)();
  389.               (void) fflush(outfile);
  390.               int_error("unknown tic type in xticdef in do_plot", NO_CARET);
  391.               break;        /* NOTREACHED */
  392.            }
  393.         }
  394.     }
  395.  
  396. /* DRAW PLOT BORDER */
  397.     (*t->linetype)(-2); /* border linetype */
  398.     if (draw_border) {
  399.         (*t->move)(xleft,ybot);
  400.         (*t->vector)(xright,ybot);
  401.         (*t->vector)(xright,ytop);
  402.         (*t->vector)(xleft,ytop);
  403.         (*t->vector)(xleft,ybot);
  404.     }
  405.  
  406. /* PLACE YLABEL */
  407.     if (strlen(ylabel) > 0) {
  408.         int x, y;
  409.  
  410.         x = ylabel_xoffset * t->h_char;
  411.         y = ylabel_yoffset * t->v_char;
  412.         if ((*t->text_angle)(1)) {
  413.             if ((*t->justify_text)(CENTRE)) {
  414.                 (*t->put_text)(x+(t->v_char),
  415.                          y+(ytop+ybot)/2, ylabel);
  416.             }
  417.             else {
  418.                 (*t->put_text)(x+(t->v_char),
  419.                            y+(ytop+ybot)/2-(t->h_char)*strlen(ylabel)/2, 
  420.                          ylabel);
  421.             }
  422.         }
  423.         else {
  424.             (void)(*t->justify_text)(LEFT);
  425.             (*t->put_text)(x,y+ytop+(t->v_char), ylabel);
  426.         }
  427.         (void)(*t->text_angle)(0);
  428.     }
  429.  
  430. /* PLACE XLABEL */
  431.     if (strlen(xlabel) > 0) {
  432.         int x, y;
  433.  
  434.         x = xlabel_xoffset * t->h_char;
  435.         y = xlabel_yoffset * t->v_char;
  436.  
  437.             if ((*t->justify_text)(CENTRE)) 
  438.             (*t->put_text)(x+(xleft+xright)/2,
  439.                        y+ybot-2*(t->v_char), xlabel);
  440.             else
  441.             (*t->put_text)(x+(xleft+xright)/2 - strlen(xlabel)*(t->h_char)/2,
  442.                            y+ybot-2*(t->v_char), xlabel);
  443.     }
  444.  
  445. /* PLACE TITLE */
  446.     if (strlen(title) > 0) {
  447.         int x, y;
  448.  
  449.         x = title_xoffset * t->h_char;
  450.         y = title_yoffset * t->v_char;
  451.  
  452.             if ((*t->justify_text)(CENTRE))
  453.             (*t->put_text)(x+(xleft+xright)/2,
  454.                        y+ytop+(t->v_char), title);
  455.             else
  456.             (*t->put_text)(x+(xleft+xright)/2 - strlen(title)*(t->h_char)/2,
  457.                        y+ytop+(t->v_char), title);
  458.     }
  459.  
  460.  
  461. /* PLACE TIMEDATE */
  462.     if (timedate) {
  463.         int x, y;
  464.  
  465.         x = time_xoffset * t->h_char;
  466.         y = time_yoffset * t->v_char;
  467.         dated = time( (long *) 0);
  468.         tdate = ctime( &dated);
  469.         tdate[24]='\0';
  470.         if ((*t->text_angle)(1)) {
  471.             if ((*t->justify_text)(CENTRE)) {
  472.                 (*t->put_text)(x+(t->v_char),
  473.                          y+ybot+4*(t->v_char), tdate);
  474.             }
  475.             else {
  476.                 (*t->put_text)(x+(t->v_char),
  477.                          y+ybot+4*(t->v_char)-(t->h_char)*strlen(ylabel)/2, 
  478.                          tdate);
  479.             }
  480.         }
  481.         else {
  482.             (void)(*t->justify_text)(LEFT);
  483.             (*t->put_text)(x,
  484.                          y+ybot-3*(t->v_char), tdate);
  485.         }
  486.         (void)(*t->text_angle)(0);
  487.     }
  488.  
  489. /* PLACE LABELS */
  490.     for (this_label = first_label; this_label!=NULL;
  491.             this_label=this_label->next ) {
  492.          xtemp = LogScale(this_label->x, log_x, "label", "x");
  493.          ytemp = LogScale(this_label->y, log_y, "label", "y");
  494.         if ((*t->justify_text)(this_label->pos)) {
  495.             (*t->put_text)(map_x(xtemp),map_y(ytemp),this_label->text);
  496.         }
  497.         else {
  498.             switch(this_label->pos) {
  499.                 case  LEFT:
  500.                     (*t->put_text)(map_x(xtemp),map_y(ytemp),
  501.                         this_label->text);
  502.                     break;
  503.                 case CENTRE:
  504.                     (*t->put_text)(map_x(xtemp)-
  505.                         (t->h_char)*strlen(this_label->text)/2,
  506.                         map_y(ytemp), this_label->text);
  507.                     break;
  508.                 case RIGHT:
  509.                     (*t->put_text)(map_x(xtemp)-
  510.                         (t->h_char)*strlen(this_label->text),
  511.                         map_y(ytemp), this_label->text);
  512.                     break;
  513.             }
  514.          }
  515.      }
  516.  
  517. /* PLACE ARROWS */
  518.     (*t->linetype)(0);    /* arrow line type */
  519.     for (this_arrow = first_arrow; this_arrow!=NULL;
  520.         this_arrow = this_arrow->next ) {
  521.        int sx = map_x(LogScale(this_arrow->sx, log_x, "arrow", "x"));
  522.        int sy = map_y(LogScale(this_arrow->sy, log_y, "arrow", "y"));
  523.        int ex = map_x(LogScale(this_arrow->ex, log_x, "arrow", "x"));
  524.        int ey = map_y(LogScale(this_arrow->ey, log_y, "arrow", "y"));
  525.        
  526.        (*t->arrow)(sx, sy, ex, ey, this_arrow->head);
  527.     }
  528.  
  529.  
  530. /* DRAW CURVES */
  531.     if (key == -1) {
  532.         xl = xright  - (t->h_tic) - (t->h_char)*5;
  533.         yl = ytop - (t->v_tic) - (t->v_char);
  534.     }
  535.     if (key == 1) {
  536.         xl = map_x( LogScale(key_x, log_x, "key", "x") );
  537.         yl = map_y( LogScale(key_y, log_y, "key", "y") );
  538.     }
  539.  
  540.     this_plot = plots;
  541.     for (curve = 0; curve < pcount; this_plot = this_plot->next_cp, curve++) {
  542.         (*t->linetype)(this_plot->line_type);
  543.         if (key != 0) {
  544.             if ((*t->justify_text)(RIGHT)) {
  545.                 (*t->put_text)(xl,
  546.                     yl,this_plot->title);
  547.             }
  548.             else {
  549.                 if (inrange(xl-(t->h_char)*strlen(this_plot->title), 
  550.                          xleft, xright))
  551.                  (*t->put_text)(xl-(t->h_char)*strlen(this_plot->title),
  552.                              yl,this_plot->title);
  553.             }
  554.         }
  555.  
  556.         switch(this_plot->plot_style) {
  557.             case IMPULSES: {
  558.                if (key != 0) {
  559.                   (*t->move)(xl+(t->h_char),yl);
  560.                   (*t->vector)(xl+4*(t->h_char),yl);
  561.                }
  562.                plot_impulses(this_plot, yaxis_x, xaxis_y);
  563.                break;
  564.             }
  565.             case LINES: {
  566.                if (key != 0) {
  567.                   (*t->move)(xl+(int)(t->h_char),yl);
  568.                   (*t->vector)(xl+(int)(4*(t->h_char)),yl);
  569.                }
  570.                plot_lines(this_plot);
  571.                break;
  572.             }
  573.             case POINTS: {
  574.                if (key != 0) {
  575.                   (*t->point)(xl+2*(t->h_char),yl,
  576.                             this_plot->point_type);
  577.                }
  578.                plot_points(this_plot);
  579.                break;
  580.             }
  581.             case LINESPOINTS: {
  582.                /* put lines */
  583.                if (key != 0) {
  584.                   (*t->move)(xl+(t->h_char),yl);
  585.                   (*t->vector)(xl+4*(t->h_char),yl);
  586.                }
  587.                plot_lines(this_plot);
  588.  
  589.                /* put points */
  590.                if (key != 0) {
  591.                   (*t->point)(xl+2*(t->h_char),yl,
  592.                             this_plot->point_type);
  593.                }
  594.                plot_points(this_plot);
  595.                break;
  596.             }
  597.             case DOTS: {
  598.                if (key != 0) {
  599.                   (*t->point)(xl+2*(t->h_char),yl, -1);
  600.                }
  601.                plot_dots(this_plot);
  602.                break;
  603.             }
  604.             case ERRORBARS: {
  605.                if (key != 0) {
  606.                   (*t->point)(xl+2*(t->h_char),yl,
  607.                             this_plot->point_type);
  608.                }
  609.                plot_points(this_plot);
  610.  
  611.                /* for functions, just like POINTS */
  612.                if (this_plot->plot_type == DATA) {
  613.                   if (key != 0) {
  614.                      (*t->move)(xl+(t->h_char),yl);
  615.                      (*t->vector)(xl+4*(t->h_char),yl);
  616.                      (*t->move)(xl+(t->h_char),yl+ERRORBARTIC);
  617.                      (*t->vector)(xl+(t->h_char),yl-ERRORBARTIC);
  618.                      (*t->move)(xl+4*(t->h_char),yl+ERRORBARTIC);
  619.                      (*t->vector)(xl+4*(t->h_char),yl-ERRORBARTIC);
  620.                   }
  621.                   plot_bars(this_plot);
  622.                }
  623.                break;
  624.             }
  625.         }
  626.         yl = yl - (t->v_char);
  627.     }
  628.     (*t->text)();
  629.     (void) fflush(outfile);
  630. }
  631.  
  632. /* plot_impulses:
  633.  * Plot the curves in IMPULSES style
  634.  */
  635. void
  636. plot_impulses(plot, yaxis_x, xaxis_y)
  637.     struct curve_points *plot;
  638.     int yaxis_x, xaxis_y;
  639. {
  640.     int i;
  641.     int x,y;
  642.     struct termentry *t = &term_tbl[term];
  643.  
  644.     for (i = 0; i < plot->p_count; i++) {
  645.        switch (plot->points[i].type) {
  646.           case INRANGE: {
  647.              x = map_x(plot->points[i].x);
  648.              y = map_y(plot->points[i].y);
  649.              break;
  650.           }
  651.           case OUTRANGE: {
  652.              if (!inrange(plot->points[i].x, x_min,x_max))
  653.                continue;
  654.              x = map_x(plot->points[i].x);
  655.              if ((y_min < y_max 
  656.                  && plot->points[i].y < y_min)
  657.                 || (y_max < y_min 
  658.                     && plot->points[i].y > y_min))
  659.                y = map_y(y_min);
  660.              if ((y_min < y_max 
  661.                  && plot->points[i].y > y_max)
  662.                 || (y_max<y_min 
  663.                     && plot->points[i].y < y_max))
  664.                y = map_y(y_max);
  665.              break;
  666.           }
  667.           default:        /* just a safety */
  668.           case UNDEFINED: {
  669.              continue;
  670.           }
  671.        }
  672.                     
  673.        if (polar)
  674.           (*t->move)(yaxis_x,xaxis_y);
  675.        else
  676.           (*t->move)(x,xaxis_y);
  677.        (*t->vector)(x,y);
  678.     }
  679.  
  680. }
  681.  
  682. /* plot_lines:
  683.  * Plot the curves in LINES style
  684.  */
  685. void
  686. plot_lines(plot)
  687.     struct curve_points *plot;
  688. {
  689.     int i;                /* point index */
  690.     int x,y;                /* point in terminal coordinates */
  691.     struct termentry *t = &term_tbl[term];
  692.     enum coord_type prev = UNDEFINED; /* type of previous point */
  693.     double ex, ey;            /* an edge point */
  694.     double lx[2], ly[2];        /* two edge points */
  695.  
  696.     for (i = 0; i < plot->p_count; i++) {
  697.        switch (plot->points[i].type) {
  698.           case INRANGE: {
  699.              x = map_x(plot->points[i].x);
  700.              y = map_y(plot->points[i].y);
  701.  
  702.              if (prev == INRANGE) {
  703.                 (*t->vector)(x,y);
  704.              } else if (prev == OUTRANGE) {
  705.                 /* from outrange to inrange */
  706.                 if (!clip_lines1) {
  707.                     (*t->move)(x,y);
  708.                 } else {
  709.                     edge_intersect(plot->points, i, &ex, &ey);
  710.                     (*t->move)(map_x(ex), map_y(ey));
  711.                     (*t->vector)(x,y);
  712.                 }
  713.              } else {        /* prev == UNDEFINED */
  714.                 (*t->move)(x,y);
  715.                 (*t->vector)(x,y);
  716.              }
  717.                     
  718.              break;
  719.           }
  720.           case OUTRANGE: {
  721.              if (prev == INRANGE) {
  722.                 /* from inrange to outrange */
  723.                 if (clip_lines1) {
  724.                     edge_intersect(plot->points, i, &ex, &ey);
  725.                     (*t->vector)(map_x(ex), map_y(ey));
  726.                 }
  727.              } else if (prev == OUTRANGE) {
  728.                 /* from outrange to outrange */
  729.                 if (clip_lines2) {
  730.                     if (two_edge_intersect(plot->points, i, lx, ly)) {
  731.                        (*t->move)(map_x(lx[0]), map_y(ly[0]));
  732.                        (*t->vector)(map_x(lx[1]), map_y(ly[1]));
  733.                     }
  734.                 }
  735.              }
  736.              break;
  737.           }
  738.           default:        /* just a safety */
  739.           case UNDEFINED: {
  740.              break;
  741.           }
  742.        }
  743.        prev = plot->points[i].type;
  744.     }
  745. }
  746.  
  747. /* plot_bars:
  748.  * Plot the curves in ERRORBARS style
  749.  *  we just plot the bars; the points are plotted in plot_points
  750.  */
  751. void
  752. plot_bars(plot)
  753.     struct curve_points *plot;
  754. {
  755.     int i;                /* point index */
  756.     struct termentry *t = &term_tbl[term];
  757.     double x;                /* position of the bar */
  758.     double ylow, yhigh;        /* the ends of the bars */
  759.     unsigned int xM, ylowM, yhighM; /* the mapped version of above */
  760.     BOOLEAN low_inrange, high_inrange;
  761.     int tic = ERRORBARTIC;
  762.     
  763.     for (i = 0; i < plot->p_count; i++) {
  764.        /* undefined points don't count */
  765.        if (plot->points[i].type == UNDEFINED)
  766.         continue;
  767.  
  768.        /* check to see if in xrange */
  769.        x = plot->points[i].x;
  770.        if (! inrange(x, x_min, x_max))
  771.         continue;
  772.        xM = map_x(x);
  773.  
  774.        /* find low and high points of bar, and check yrange */
  775.        yhigh = plot->points[i].yhigh;
  776.        ylow = plot->points[i].ylow;
  777.  
  778.        high_inrange = inrange(yhigh, y_min,y_max);
  779.        low_inrange = inrange(ylow, y_min,y_max);
  780.  
  781.        /* compute the plot position of yhigh */
  782.        if (high_inrange)
  783.         yhighM = map_y(yhigh);
  784.        else if (samesign(yhigh-y_max, y_max-y_min))
  785.         yhighM = map_y(y_max);
  786.        else
  787.         yhighM = map_y(y_min);
  788.        
  789.        /* compute the plot position of ylow */
  790.        if (low_inrange)
  791.         ylowM = map_y(ylow);
  792.        else if (samesign(ylow-y_max, y_max-y_min))
  793.         ylowM = map_y(y_max);
  794.        else
  795.         ylowM = map_y(y_min);
  796.  
  797.        if (!high_inrange && !low_inrange && ylowM == yhighM)
  798.         /* both out of range on the same side */
  799.           continue;
  800.  
  801.        /* by here everything has been mapped */
  802.        (*t->move)(xM, ylowM);
  803.        (*t->vector)(xM, yhighM); /* draw the main bar */
  804.        (*t->move)(xM-tic, ylowM); /* draw the bottom tic */
  805.        (*t->vector)(xM+tic, ylowM);
  806.        (*t->move)(xM-tic, yhighM); /* draw the top tic */
  807.        (*t->vector)(xM+tic, yhighM);
  808.     }
  809. }
  810.  
  811. /* plot_points:
  812.  * Plot the curves in POINTS style
  813.  */
  814. void
  815. plot_points(plot)
  816.     struct curve_points *plot;
  817. {
  818.     int i;
  819.     int x,y;
  820.     struct termentry *t = &term_tbl[term];
  821.  
  822.     for (i = 0; i < plot->p_count; i++) {
  823.        if (plot->points[i].type == INRANGE) {
  824.           x = map_x(plot->points[i].x);
  825.           y = map_y(plot->points[i].y);
  826.           /* do clipping if necessary */
  827.           if (!clip_points ||
  828.              (   x >= xleft + t->h_tic  && y >= ybot + t->v_tic 
  829.               && x <= xright - t->h_tic && y <= ytop - t->v_tic))
  830.             (*t->point)(x,y, plot->point_type);
  831.        }
  832.     }
  833. }
  834.  
  835. /* plot_dots:
  836.  * Plot the curves in DOTS style
  837.  */
  838. void
  839. plot_dots(plot)
  840.     struct curve_points *plot;
  841. {
  842.     int i;
  843.     int x,y;
  844.     struct termentry *t = &term_tbl[term];
  845.  
  846.     for (i = 0; i < plot->p_count; i++) {
  847.        if (plot->points[i].type == INRANGE) {
  848.           x = map_x(plot->points[i].x);
  849.           y = map_y(plot->points[i].y);
  850.           /* point type -1 is a dot */
  851.           (*t->point)(x,y, -1);
  852.        }
  853.     }
  854. }
  855.  
  856. /* single edge intersection algorithm */
  857. /* Given two points, one inside and one outside the plot, return
  858.  * the point where an edge of the plot intersects the line segment defined 
  859.  * by the two points.
  860.  */
  861. void
  862. edge_intersect(points, i, ex, ey)
  863.     struct coordinate *points; /* the points array */
  864.     int i;                /* line segment from point i-1 to point i */
  865.     double *ex, *ey;        /* the point where it crosses an edge */
  866. {
  867.     /* global x_min, x_max, y_min, x_max */
  868.     double ax = points[i-1].x;
  869.     double ay = points[i-1].y;
  870.     double bx = points[i].x;
  871.     double by = points[i].y;
  872.     double x, y;            /* possible intersection point */
  873.  
  874.     if (by == ay) {
  875.        /* horizontal line */
  876.        /* assume inrange(by, y_min, y_max) */
  877.        *ey = by;        /* == ay */
  878.  
  879.        if (inrange(x_max, ax, bx))
  880.         *ex = x_max;
  881.        else if (inrange(x_min, ax, bx))
  882.         *ex = x_min;
  883.        else {
  884.         (*term_tbl[term].text)();
  885.         (void) fflush(outfile);
  886.         int_error("error in edge_intersect", NO_CARET);
  887.        }
  888.        return;
  889.     } else if (bx == ax) {
  890.        /* vertical line */
  891.        /* assume inrange(bx, x_min, x_max) */
  892.        *ex = bx;        /* == ax */
  893.  
  894.        if (inrange(y_max, ay, by))
  895.         *ey = y_max;
  896.        else if (inrange(y_min, ay, by))
  897.         *ey = y_min;
  898.        else {
  899.         (*term_tbl[term].text)();
  900.         (void) fflush(outfile);
  901.         int_error("error in edge_intersect", NO_CARET);
  902.        }
  903.        return;
  904.     }
  905.  
  906.     /* slanted line of some kind */
  907.  
  908.     /* does it intersect y_min edge */
  909.     if (inrange(y_min, ay, by) && y_min != ay && y_min != by) {
  910.        x = ax + (y_min-ay) * ((bx-ax) / (by-ay));
  911.        if (inrange(x, x_min, x_max)) {
  912.           *ex = x;
  913.           *ey = y_min;
  914.           return;            /* yes */
  915.        }
  916.     }
  917.     
  918.     /* does it intersect y_max edge */
  919.     if (inrange(y_max, ay, by) && y_max != ay && y_max != by) {
  920.        x = ax + (y_max-ay) * ((bx-ax) / (by-ay));
  921.        if (inrange(x, x_min, x_max)) {
  922.           *ex = x;
  923.           *ey = y_max;
  924.           return;            /* yes */
  925.        }
  926.     }
  927.  
  928.     /* does it intersect x_min edge */
  929.     if (inrange(x_min, ax, bx) && x_min != ax && x_min != bx) {
  930.        y = ay + (x_min-ax) * ((by-ay) / (bx-ax));
  931.        if (inrange(y, y_min, y_max)) {
  932.           *ex = x_min;
  933.           *ey = y;
  934.           return;
  935.        }
  936.     }
  937.  
  938.     /* does it intersect x_max edge */
  939.     if (inrange(x_max, ax, bx) && x_max != ax && x_max != bx) {
  940.        y = ay + (x_max-ax) * ((by-ay) / (bx-ax));
  941.        if (inrange(y, y_min, y_max)) {
  942.           *ex = x_max;
  943.           *ey = y;
  944.           return;
  945.        }
  946.     }
  947.  
  948.     /* It is possible for one or two of the [ab][xy] values to be -VERYLARGE.
  949.     * If ax=bx=-VERYLARGE or ay=by=-VERYLARGE we have already returned 
  950.     * FALSE above. Otherwise we fall through all the tests above. 
  951.     * If two are -VERYLARGE, it is ax=ay=-VERYLARGE or bx=by=-VERYLARGE 
  952.     * since either a or b must be INRANGE. 
  953.     * Note that for ax=ay=-VERYLARGE or bx=by=-VERYLARGE we can do nothing.
  954.     * Handle them carefully here. As yet we have no way for them to be 
  955.     * +VERYLARGE.
  956.     */
  957.     if (ax == -VERYLARGE) {
  958.        if (ay != -VERYLARGE) {
  959.           *ex = min(x_min, x_max);
  960.           *ey = by;
  961.           return;
  962.        }
  963.     } else if (bx == -VERYLARGE) {
  964.        if (by != -VERYLARGE) {
  965.           *ex = min(x_min, x_max);
  966.           *ey = ay;
  967.           return;
  968.        }
  969.     } else if (ay == -VERYLARGE) {
  970.        /* note we know ax != -VERYLARGE */
  971.        *ex = bx;
  972.        *ey = min(y_min, y_max);
  973.        return;
  974.     } else if (by == -VERYLARGE) {
  975.        /* note we know bx != -VERYLARGE */
  976.        *ex = ax;
  977.        *ey = min(y_min, y_max);
  978.        return;
  979.     }
  980.  
  981.     /* If we reach here, then either one point is (-VERYLARGE,-VERYLARGE), 
  982.     * or the inrange point is on the edge, and
  983.      * the line segment from the outrange point does not cross any 
  984.     * other edges to get there. In either case, we return the inrange 
  985.     * point as the 'edge' intersection point. This will basically draw
  986.     * line.
  987.     */
  988.     if (points[i].type == INRANGE) {
  989.        *ex = bx; 
  990.        *ey = by;
  991.     } else {
  992.        *ex = ax; 
  993.        *ey = ay;
  994.     }
  995.     return;
  996. }
  997.  
  998. /* double edge intersection algorithm */
  999. /* Given two points, both outside the plot, return
  1000.  * the points where an edge of the plot intersects the line segment defined 
  1001.  * by the two points. There may be zero, one, two, or an infinite number
  1002.  * of intersection points. (One means an intersection at a corner, infinite
  1003.  * means overlaying the edge itself). We return FALSE when there is nothing
  1004.  * to draw (zero intersections), and TRUE when there is something to 
  1005.  * draw (the one-point case is a degenerate of the two-point case and we do 
  1006.  * not distinguish it - we draw it anyway).
  1007.  */
  1008. BOOLEAN                /* any intersection? */
  1009. two_edge_intersect(points, i, lx, ly)
  1010.     struct coordinate *points; /* the points array */
  1011.     int i;                /* line segment from point i-1 to point i */
  1012.     double *lx, *ly;        /* lx[2], ly[2]: points where it crosses edges */
  1013. {
  1014.     /* global x_min, x_max, y_min, x_max */
  1015.     double ax = points[i-1].x;
  1016.     double ay = points[i-1].y;
  1017.     double bx = points[i].x;
  1018.     double by = points[i].y;
  1019.     double x, y;            /* possible intersection point */
  1020.     BOOLEAN intersect = FALSE;
  1021.  
  1022.     if (by == ay) {
  1023.        /* horizontal line */
  1024.        /* y coord must be in range, and line must span both x_min and x_max */
  1025.        /* note that spanning x_min implies spanning x_max */
  1026.        if (inrange(by, y_min, y_max) && inrange(x_min, ax, bx)) {
  1027.           *lx++ = x_min;
  1028.           *ly++ = by;
  1029.           *lx++ = x_max;
  1030.           *ly++ = by;
  1031.           return(TRUE);
  1032.        } else
  1033.         return(FALSE);
  1034.     } else if (bx == ax) {
  1035.        /* vertical line */
  1036.        /* x coord must be in range, and line must span both y_min and y_max */
  1037.        /* note that spanning y_min implies spanning y_max */
  1038.        if (inrange(bx, x_min, x_max) && inrange(y_min, ay, by)) {
  1039.           *lx++ = bx;
  1040.           *ly++ = y_min;
  1041.           *lx++ = bx;
  1042.           *ly++ = y_max;
  1043.           return(TRUE);
  1044.        } else
  1045.         return(FALSE);
  1046.     }
  1047.  
  1048.     /* slanted line of some kind */
  1049.     /* there can be only zero or two intersections below */
  1050.  
  1051.     /* does it intersect y_min edge */
  1052.     if (inrange(y_min, ay, by)) {
  1053.        x = ax + (y_min-ay) * ((bx-ax) / (by-ay));
  1054.        if (inrange(x, x_min, x_max)) {
  1055.           *lx++ = x;
  1056.           *ly++ = y_min;
  1057.           intersect = TRUE;
  1058.        }
  1059.     }
  1060.     
  1061.     /* does it intersect y_max edge */
  1062.     if (inrange(y_max, ay, by)) {
  1063.        x = ax + (y_max-ay) * ((bx-ax) / (by-ay));
  1064.        if (inrange(x, x_min, x_max)) {
  1065.           *lx++ = x;
  1066.           *ly++ = y_max;
  1067.           intersect = TRUE;
  1068.        }
  1069.     }
  1070.  
  1071.     /* does it intersect x_min edge */
  1072.     if (inrange(x_min, ax, bx)) {
  1073.        y = ay + (x_min-ax) * ((by-ay) / (bx-ax));
  1074.        if (inrange(y, y_min, y_max)) {
  1075.           *lx++ = x_min;
  1076.           *ly++ = y;
  1077.           intersect = TRUE;
  1078.        }
  1079.     }
  1080.  
  1081.     /* does it intersect x_max edge */
  1082.     if (inrange(x_max, ax, bx)) {
  1083.        y = ay + (x_max-ax) * ((by-ay) / (bx-ax));
  1084.        if (inrange(y, y_min, y_max)) {
  1085.           *lx++ = x_max;
  1086.           *ly++ = y;
  1087.           intersect = TRUE;
  1088.        }
  1089.     }
  1090.  
  1091.     if (intersect)
  1092.      return(TRUE);
  1093.  
  1094.     /* It is possible for one or more of the [ab][xy] values to be -VERYLARGE.
  1095.     * If ax=bx=-VERYLARGE or ay=by=-VERYLARGE we have already returned
  1096.     * FALSE above.
  1097.     * Note that for ax=ay=-VERYLARGE or bx=by=-VERYLARGE we can do nothing.
  1098.     * Otherwise we fall through all the tests above. 
  1099.     * Handle them carefully here. As yet we have no way for them to be +VERYLARGE.
  1100.     */
  1101.     if (ax == -VERYLARGE) {
  1102.        if (ay != -VERYLARGE
  1103.           && inrange(by, y_min, y_max) && inrange(x_max, ax, bx)) {
  1104.           *lx++ = x_min;
  1105.           *ly = by;
  1106.           *lx++ = x_max;
  1107.           *ly = by;
  1108.           intersect = TRUE;
  1109.        }
  1110.     } else if (bx == -VERYLARGE) {
  1111.        if (by != -VERYLARGE
  1112.           && inrange(ay, y_min, y_max) && inrange(x_max, ax, bx)) {
  1113.           *lx++ = x_min;
  1114.           *ly = ay;
  1115.           *lx++ = x_max;
  1116.           *ly = ay;
  1117.           intersect = TRUE;
  1118.        }
  1119.     } else if (ay == -VERYLARGE) {
  1120.        /* note we know ax != -VERYLARGE */
  1121.        if (inrange(bx, x_min, x_max) && inrange(y_max, ay, by)) {
  1122.           *lx++ = bx;
  1123.           *ly = y_min;
  1124.           *lx++ = bx;
  1125.           *ly = y_max;
  1126.           intersect = TRUE;
  1127.        }
  1128.     } else if (by == -VERYLARGE) {
  1129.        /* note we know bx != -VERYLARGE */
  1130.        if (inrange(ax, x_min, x_max) && inrange(y_max, ay, by)) {
  1131.           *lx++ = ax;
  1132.           *ly = y_min;
  1133.           *lx++ = ax;
  1134.           *ly = y_max;
  1135.           intersect = TRUE;
  1136.        }
  1137.     }
  1138.  
  1139.     return(intersect);
  1140. }
  1141.  
  1142. /* Polar transform of all curves */
  1143. /* Original code by John Campbell (CAMPBELL@NAUVAX.bitnet) */
  1144. polar_xform (plots, pcount)
  1145.     struct curve_points *plots;
  1146.     int pcount;            /* count of curves in plots array */
  1147. {
  1148.      struct curve_points *this_plot;
  1149.      int curve;            /* loop var, for curves */
  1150.      register int i, p_cnt;    /* loop/limit var, for points */
  1151.      struct coordinate *pnts;    /* abbrev. for points array */
  1152.     double x, y;            /* new cartesian value */
  1153.     BOOLEAN anydefined = FALSE;
  1154.     double d2r;
  1155.  
  1156.     if(angles_format == ANGLES_DEGREES){
  1157.         d2r = DEG2RAD;
  1158.     } else {
  1159.         d2r = 1.0;
  1160.     }
  1161.  
  1162. /*
  1163.     Cycle through all the plots converting polar to rectangular.
  1164.      If autoscaling, adjust max and mins. Ignore previous values.
  1165.     If not autoscaling, use the yrange for both x and y ranges.
  1166. */
  1167.     if (autoscale_ly) {
  1168.         x_min = VERYLARGE;
  1169.         y_min = VERYLARGE;
  1170.         x_max = -VERYLARGE;
  1171.         y_max = -VERYLARGE;
  1172.         autoscale_lx = TRUE;
  1173.     } else {
  1174.         x_min = y_min;
  1175.         x_max = y_max;
  1176.     }
  1177.     
  1178.     this_plot = plots;
  1179.     for (curve = 0; curve < pcount; this_plot = this_plot->next_cp, curve++) {
  1180.         p_cnt = this_plot->p_count;
  1181.         pnts = &(this_plot->points[0]);
  1182.  
  1183.     /*    Convert to cartesian all points in this curve. */
  1184.         for (i = 0; i < p_cnt; i++) {
  1185.             if (pnts[i].type != UNDEFINED) {
  1186.                  anydefined = TRUE;
  1187.                  /* modify points to reset origin and from degrees */
  1188.                  pnts[i].y -= rmin;
  1189.                  pnts[i].x *= d2r;
  1190.                  /* convert to cartesian coordinates */
  1191.                 x = pnts[i].y*cos(pnts[i].x);
  1192.                 y = pnts[i].y*sin(pnts[i].x);
  1193.                 pnts[i].x = x;
  1194.                 pnts[i].y = y;
  1195.                 if (autoscale_ly) {
  1196.                     if (x_min > x) x_min = x;
  1197.                     if (x_max < x) x_max = x;
  1198.                     if (y_min > y) y_min = y;
  1199.                     if (y_max < y) y_max = y;
  1200.                     pnts[i].type = INRANGE;
  1201.                 } else if(inrange(x, x_min, x_max) && inrange(y, y_min, y_max))
  1202.                   pnts[i].type = INRANGE;
  1203.                 else
  1204.                   pnts[i].type = OUTRANGE;
  1205.             }
  1206.         }    
  1207.     }
  1208.  
  1209.     if (autoscale_lx && anydefined && fabs(x_max - x_min) < zero) {
  1210.         /* This happens at least for the plot of 1/cos(x) (vertical line). */
  1211.         fprintf(stderr, "Warning: empty x range [%g:%g], ", x_min,x_max);
  1212.         if (x_min == 0.0) {
  1213.            x_min = -1; 
  1214.            x_max = 1;
  1215.         } else {
  1216.            x_min *= 0.9;
  1217.            x_max *= 1.1;
  1218.         }
  1219.         fprintf(stderr, "adjusting to [%g:%g]\n", x_min,x_max);
  1220.     }
  1221.     if (autoscale_ly && anydefined && fabs(y_max - y_min) < zero) {
  1222.         /* This happens at least for the plot of 1/sin(x) (horiz. line). */
  1223.         fprintf(stderr, "Warning: empty y range [%g:%g], ", y_min, y_max);
  1224.         if (y_min == 0.0) {
  1225.            y_min = -1;
  1226.            y_max = 1;
  1227.         } else {
  1228.            y_min *= 0.9;
  1229.            y_max *= 1.1;
  1230.         }
  1231.         fprintf(stderr, "adjusting to [%g:%g]\n", y_min, y_max);
  1232.     }
  1233. }
  1234.  
  1235. /* DRAW_YTICS: draw a regular tic series, y axis */
  1236. draw_ytics(start, incr, end)
  1237.         double start, incr, end; /* tic series definition */
  1238.         /* assume start < end, incr > 0 */
  1239. {
  1240.     double ticplace;
  1241.     int ltic;            /* for mini log tics */
  1242.     double lticplace;    /* for mini log tics */
  1243.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  1244.  
  1245.     if (end == VERYLARGE)            /* for user-def series */
  1246.         end = max(y_min,y_max);
  1247.  
  1248.     /* limit to right side of plot */
  1249.     end = min(end, max(y_min,y_max));
  1250.  
  1251.     /* to allow for rounding errors */
  1252.     ticmin = min(y_min,y_max) - SIGNIF*incr;
  1253.     ticmax = max(y_min,y_max) + SIGNIF*incr;
  1254.     end = end + SIGNIF*incr; 
  1255.  
  1256.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  1257.         if ( inrange(ticplace,ticmin,ticmax) )
  1258.             ytick(ticplace, yformat, incr, 1.0);
  1259.         if (log_y && incr == 1.0) {
  1260.             /* add mini-ticks to log scale ticmarks */
  1261.             int lstart, linc;
  1262.             if ((end - start) >= 10)
  1263.             {
  1264.             lstart = 10; /* No little ticks */
  1265.             linc = 5;
  1266.             }
  1267.             else if((end - start) >= 5)
  1268.             {
  1269.             lstart = 2; /* 4 per decade */
  1270.             linc = 3;
  1271.             }
  1272.             else
  1273.             {
  1274.             lstart = 2; /* 9 per decade */
  1275.             linc = 1;
  1276.             }
  1277.             for (ltic = lstart; ltic <= 9; ltic += linc) {
  1278.                 lticplace = ticplace+log10((double)ltic);
  1279.                 if ( inrange(lticplace,ticmin,ticmax) )
  1280.                     ytick(lticplace, "\0", incr, 0.5);
  1281.             }
  1282.         }
  1283.     }
  1284. }
  1285.  
  1286. /* DRAW_XTICS: draw a regular tic series, x axis */
  1287. draw_xtics(start, incr, end)
  1288.         double start, incr, end; /* tic series definition */
  1289.         /* assume start < end, incr > 0 */
  1290. {
  1291.     double ticplace;
  1292.     int ltic;            /* for mini log tics */
  1293.     double lticplace;    /* for mini log tics */
  1294.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  1295.  
  1296.     if (end == VERYLARGE)            /* for user-def series */
  1297.         end = max(x_min,x_max);
  1298.  
  1299.     /* limit to right side of plot */
  1300.     end = min(end, max(x_min,x_max));
  1301.  
  1302.     /* to allow for rounding errors */
  1303.     ticmin = min(x_min,x_max) - SIGNIF*incr;
  1304.     ticmax = max(x_min,x_max) + SIGNIF*incr;
  1305.     end = end + SIGNIF*incr; 
  1306.  
  1307.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  1308.         if ( inrange(ticplace,ticmin,ticmax) )
  1309.             xtick(ticplace, xformat, incr, 1.0);
  1310.         if (log_x && incr == 1.0) {
  1311.             /* add mini-ticks to log scale ticmarks */
  1312.             int lstart, linc;
  1313.             if ((end - start) >= 10)
  1314.             {
  1315.             lstart = 10; /* No little ticks */
  1316.             linc = 5;
  1317.             }
  1318.             else if((end - start) >= 5)
  1319.             {
  1320.             lstart = 2; /* 4 per decade */
  1321.             linc = 3;
  1322.             }
  1323.             else
  1324.             {
  1325.             lstart = 2; /* 9 per decade */
  1326.             linc = 1;
  1327.             }
  1328.             for (ltic = lstart; ltic <= 9; ltic += linc) {
  1329.                 lticplace = ticplace+log10((double)ltic);
  1330.                 if ( inrange(lticplace,ticmin,ticmax) )
  1331.                     xtick(lticplace, "\0", incr, 0.5);
  1332.             }
  1333.         }
  1334.     }
  1335. }
  1336.  
  1337. /* DRAW_SERIES_YTICS: draw a user tic series, y axis */
  1338. draw_series_ytics(start, incr, end)
  1339.         double start, incr, end; /* tic series definition */
  1340.         /* assume start < end, incr > 0 */
  1341. {
  1342.     double ticplace, place;
  1343.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  1344.     double spacing = log_y ? log10(incr) : incr;
  1345.  
  1346.     if (end == VERYLARGE)
  1347.         end = max(CheckLog(log_y, y_min), CheckLog(log_y, y_max));
  1348.     else
  1349.       /* limit to right side of plot */
  1350.       end = min(end, max(CheckLog(log_y, y_min), CheckLog(log_y, y_max)));
  1351.  
  1352.     /* to allow for rounding errors */
  1353.     ticmin = min(y_min,y_max) - SIGNIF*incr;
  1354.     ticmax = max(y_min,y_max) + SIGNIF*incr;
  1355.     end = end + SIGNIF*incr; 
  1356.  
  1357.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  1358.         place = (log_y ? log10(ticplace) : ticplace);
  1359.         if ( inrange(place,ticmin,ticmax) )
  1360.          ytick(place, yformat, spacing, 1.0);
  1361.     }
  1362. }
  1363.  
  1364.  
  1365. /* DRAW_SERIES_XTICS: draw a user tic series, x axis */
  1366. draw_series_xtics(start, incr, end)
  1367.         double start, incr, end; /* tic series definition */
  1368.         /* assume start < end, incr > 0 */
  1369. {
  1370.     double ticplace, place;
  1371.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  1372.     double spacing = log_x ? log10(incr) : incr;
  1373.  
  1374.     if (end == VERYLARGE)
  1375.         end = max(CheckLog(log_x, x_min), CheckLog(log_x, x_max));
  1376.     else
  1377.       /* limit to right side of plot */
  1378.       end = min(end, max(CheckLog(log_x, x_min), CheckLog(log_x, x_max)));
  1379.  
  1380.     /* to allow for rounding errors */
  1381.     ticmin = min(x_min,x_max) - SIGNIF*incr;
  1382.     ticmax = max(x_min,x_max) + SIGNIF*incr;
  1383.     end = end + SIGNIF*incr; 
  1384.  
  1385.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  1386.         place = (log_x ? log10(ticplace) : ticplace);
  1387.         if ( inrange(place,ticmin,ticmax) )
  1388.          xtick(place, xformat, spacing, 1.0);
  1389.     }
  1390. }
  1391.  
  1392. /* DRAW_SET_YTICS: draw a user tic set, y axis */
  1393. draw_set_ytics(list)
  1394.     struct ticmark *list;    /* list of tic marks */
  1395. {
  1396.     double ticplace;
  1397.     double incr = (y_max - y_min) / 10;
  1398.     /* global x_min, x_max, xscale, y_min, y_max, yscale */
  1399.  
  1400.     while (list != NULL) {
  1401.        ticplace = (log_y ? log10(list->position) : list->position);
  1402.        if ( inrange(ticplace, y_min, y_max)         /* in range */
  1403.           || NearlyEqual(ticplace, y_min, incr)    /* == y_min */
  1404.           || NearlyEqual(ticplace, y_max, incr))    /* == y_max */
  1405.         ytick(ticplace, list->label, incr, 1.0);
  1406.  
  1407.        list = list->next;
  1408.     }
  1409. }
  1410.  
  1411. /* DRAW_SET_XTICS: draw a user tic set, x axis */
  1412. draw_set_xtics(list)
  1413.     struct ticmark *list;    /* list of tic marks */
  1414. {
  1415.     double ticplace;
  1416.     double incr = (x_max - x_min) / 10;
  1417.     /* global x_min, x_max, xscale, y_min, y_max, yscale */
  1418.  
  1419.     while (list != NULL) {
  1420.        ticplace = (log_x ? log10(list->position) : list->position);
  1421.        if ( inrange(ticplace, x_min, x_max)         /* in range */
  1422.           || NearlyEqual(ticplace, x_min, incr)    /* == x_min */
  1423.           || NearlyEqual(ticplace, x_max, incr))    /* == x_max */
  1424.         xtick(ticplace, list->label, incr, 1.0);
  1425.  
  1426.        list = list->next;
  1427.     }
  1428. }
  1429.  
  1430. /* draw and label a y-axis ticmark */
  1431. ytick(place, text, spacing, ticscale)
  1432.         double place;                   /* where on axis to put it */
  1433.         char *text;                     /* optional text label */
  1434.         double spacing;         /* something to use with checkzero */
  1435.         double ticscale;         /* scale factor for tic mark (0..1] */
  1436. {
  1437.     register struct termentry *t = &term_tbl[term];
  1438.     char ticlabel[101];
  1439.     int ticsize = (int)((t->h_tic) * ticscale);
  1440.  
  1441.     place = CheckZero(place,spacing); /* to fix rounding error near zero */
  1442.     if (grid) {
  1443.            (*t->linetype)(-1);  /* axis line type */
  1444.            /* do not put a rectangular grid on a polar plot */
  1445.        if( !polar){
  1446.          (*t->move)(xleft, map_y(place));
  1447.          (*t->vector)(xright, map_y(place));
  1448.            }
  1449.        (*t->linetype)(-2); /* border linetype */
  1450.     }
  1451.     if (tic_in) {
  1452.       /* if polar plot, put the tics along the axes */
  1453.       if( polar){
  1454.            (*t->move)(map_x(ZERO),map_y(place));
  1455.            (*t->vector)(map_x(ZERO) + ticsize, map_y(place));
  1456.            (*t->move)(map_x(ZERO), map_y(place));
  1457.            (*t->vector)(map_x(ZERO) - ticsize, map_y(place));
  1458.      } else {
  1459.        (*t->move)(xleft, map_y(place));
  1460.            (*t->vector)(xleft + ticsize, map_y(place));
  1461.            (*t->move)(xright, map_y(place));
  1462.            (*t->vector)(xright - ticsize, map_y(place));
  1463.      }
  1464.     } else {
  1465.       if( polar){
  1466.            (*t->move)(map_x(ZERO), map_y(place));
  1467.            (*t->vector)(map_x(ZERO) - ticsize, map_y(place));
  1468.      }else{
  1469.            (*t->move)(xleft, map_y(place));
  1470.            (*t->vector)(xleft - ticsize, map_y(place));
  1471.      }
  1472.     }
  1473.  
  1474.     /* label the ticmark */
  1475.     if (text == NULL) 
  1476.      text = yformat;
  1477.     
  1478.     if( polar){
  1479.       (void) sprintf(ticlabel, text, CheckLog(log_y,fabs( place)+rmin));
  1480.       if ((*t->justify_text)(RIGHT)) {
  1481.        (*t->put_text)(map_x(ZERO)-(t->h_char),
  1482.                    map_y(place), ticlabel);
  1483.      } else {
  1484.        (*t->put_text)(map_x(ZERO)-(t->h_char)*(strlen(ticlabel)+1),
  1485.                    map_y(place), ticlabel);
  1486.      }
  1487.     } else {
  1488.     
  1489.       (void) sprintf(ticlabel, text, CheckLog(log_y, place));
  1490.       if ((*t->justify_text)(RIGHT)) {
  1491.        (*t->put_text)(xleft-(t->h_char),
  1492.                    map_y(place), ticlabel);
  1493.      } else {
  1494.        (*t->put_text)(xleft-(t->h_char)*(strlen(ticlabel)+1),
  1495.                    map_y(place), ticlabel);
  1496.      }
  1497.     }
  1498. }
  1499.  
  1500. /* draw and label an x-axis ticmark */
  1501. xtick(place, text, spacing, ticscale)
  1502.         double place;                   /* where on axis to put it */
  1503.         char *text;                     /* optional text label */
  1504.         double spacing;         /* something to use with checkzero */
  1505.         double ticscale;         /* scale factor for tic mark (0..1] */
  1506. {
  1507.     register struct termentry *t = &term_tbl[term];
  1508.     char ticlabel[101];
  1509.     int ticsize = (int)((t->v_tic) * ticscale);
  1510.  
  1511.     place = CheckZero(place,spacing); /* to fix rounding error near zero */
  1512.     if (grid) {
  1513.            (*t->linetype)(-1);  /* axis line type */
  1514.            if( !polar){
  1515.          (*t->move)(map_x(place), ybot);
  1516.          (*t->vector)(map_x(place), ytop);
  1517.            }
  1518.        (*t->linetype)(-2); /* border linetype */
  1519.     }
  1520.     if (tic_in) {
  1521.       if( polar){
  1522.            (*t->move)(map_x(place), map_y(ZERO));
  1523.            (*t->vector)(map_x(place), map_y(ZERO) + ticsize);
  1524.            (*t->move)(map_x(place), map_y(ZERO));
  1525.            (*t->vector)(map_x(place), map_y(ZERO) - ticsize);
  1526.      } else{
  1527.            (*t->move)(map_x(place), ybot);
  1528.            (*t->vector)(map_x(place), ybot + ticsize);
  1529.            (*t->move)(map_x(place), ytop);
  1530.            (*t->vector)(map_x(place), ytop - ticsize);
  1531.      }
  1532.     } else {
  1533.       if( polar){
  1534.            (*t->move)(map_x(place), map_y(ZERO));
  1535.            (*t->vector)(map_x(place), map_y(ZERO) - ticsize);
  1536.      }else{
  1537.            (*t->move)(map_x(place), ybot);
  1538.            (*t->vector)(map_x(place), ybot - ticsize);
  1539.      }
  1540.     }
  1541.     
  1542.     /* label the ticmark */
  1543.     if (text == NULL)
  1544.      text = xformat;
  1545.  
  1546.     if(polar){
  1547.       (void) sprintf(ticlabel, text, CheckLog(log_x, fabs(place)+rmin));
  1548.       if ((*t->justify_text)(CENTRE)) {
  1549.        (*t->put_text)(map_x(place),
  1550.                    map_y(ZERO)-(t->v_char), ticlabel);
  1551.      } else {
  1552.        (*t->put_text)(map_x(place)-(t->h_char)*strlen(ticlabel)/2,
  1553.                    map_y(ZERO)-(t->v_char), ticlabel);
  1554.      }
  1555.     }else{
  1556.  
  1557.       (void) sprintf(ticlabel, text, CheckLog(log_x, place));
  1558.       if ((*t->justify_text)(CENTRE)) {
  1559.        (*t->put_text)(map_x(place),
  1560.                    ybot-(t->v_char), ticlabel);
  1561.      } else {
  1562.        (*t->put_text)(map_x(place)-(t->h_char)*strlen(ticlabel)/2,
  1563.                    ybot-(t->v_char), ticlabel);
  1564.      }
  1565.     }
  1566. }
  1567.